%main = readPiece(piece,main,pos)
%   This function reads the SMILES information that can be obtained from
%   the input string such as: What atoms are in there, what type of bonds
%   there are, whether there are rings and sidechains. It stores this
%   information in the struct that it outputs: 'main'. Every field contains
%   another piece of information to be used by other functions.
%
%   In an early stage of development this function was recursive, hence
%   that input of 'main' and 'pos' are required. The current version
%   however cuts the read piece out of the string 'piece'. This has a
%   significant lower resource cost. The options have been left in for
%   debugging purposes: now one can start with a partial main or start from
%   a certain position skipping a certain number of elements of the input
%   string 'piece'.

%%

function main = readPiece(piece,main,pos)
%% Initialize
%Loading the cell used for identifying atoms.
load('.\Core\temp\symbol.mat')

%Create the field 'branch' within 'main' at the current position to be able
%to check the existence of fields if main is completely empty:
if isempty(main)
    main(pos).branch = [];
end

%The function 'multibonds' requires the fields 'dubbondconfig' and
%'bondstype' to exist. Since this function is possible called before either
%of the fields is created, hence they are created right here.
if ~myIsField(main,'dubbondconfig')
    main.dubbondconfig = [];
end
if ~myIsField(main,'bondstype')
    main.bondstype = [];
end

%Create the field 'branch' within 'main' for similar reasons as above, but
%for other application.
main(pos).branch = [];

%% Main
%Starting at branchlvl 0 (the main branch)
branchlvl = 0;
%Starting at branchdepth 0 (start outside of sidechain)
branchdepth = 0;
%Create the field 'branch' within 'main'.
main(pos).branch = [];

%Starting at j = 0 since the increasing of j is done at the beginning of
%the while-loop
j = 0;

%While the string 'piece' is not yet empty
while ~isempty(piece)
    %Increase j by one
    j = j+1;
    %For (length(piece) to zero)-1
    for k = length(piece)-1:-1:0
        
        %See if the string from the first to the 1+k of 'piece' is an
        %element except an aromatic element
        loc = find(ismember(symbol,piece(1:1+k)),1);
        %If it is, then 'loc' is not empty
        if ~isempty(loc)
            %Run getElement to get the elements letter code, atom number,
            %type (this is always atom though).
            main = getElement(piece(1:1+k),main,pos+j-1);
            %Remember this 'k' for cutting the string 'piece'
            kstor = k;
            
            %If the current element is in a branch
            if branchdepth
                %Store the current branchlvl and branchdepth
                main(pos+j-1).branch = branchlvl;
                main(pos+j-1).branchdepth = branchdepth;
            else
                %Else store zeros in those places.
                main(pos+j-1).branch = 0;
                main(pos+j-1).branchdepth = 0;
            end
            %Break the forloop to prevent the program from finding anything
            %else than the correct.
            break
        elseif k == 0
            %Else, check for k == 0, because then the element might be
            %lowercase because of aromacity.
            %Check an uppercase version of the current piece of 'piece'
            %against the element database:
            loc = find(ismember(symbol,upper(piece(1))),1);
            
            %If this time an element has been found run it through
            %'getElement', store k, store the branchlevel and branchdepth
            %if necessary. Then break to prevent errors
            if ~isempty(loc)
                main = getElement(piece(1),main,pos+j-1);
                kstor = k;
                if branchdepth
                    main(pos+j-1).branch = branchlvl;
                    main(pos+j-1).branchdepth = branchdepth;
                else
                    main(pos+j-1).branch = 0;
                    main(pos+j-1).branchdepth = 0;
                end
                break
            end
            
            %The next statement tries to see if the piece of string
            %selected contains a ringmarker, which can either simple be an
            %integer, an integer preceded by a percentage mark or a
            %combination of those things. The function 'ringMarker' is then
            %called upon to resolve that issue en returns a main in which
            %the ringmarkers have been added and a value within 'skip' of
            %which one is subtracted and the result stored in 'kstor'. Then
            %a break to prevent errors.
            loc = str2double(piece(1));
            if ~isnan(loc) || piece(1) == '%'
                [main skip] = ringMarker(piece,main,length(main));
                kstor = skip-1;
                break
            end
        else
            %If 'loc' is empty and k ~= 0 then one many things is possible
            %and they are all checked here in this switch of the first
            %element of piece:
            switch piece(1)
                %In all cases:
                %'kstor' is set to 0 to cut of this element AND
                %'break' is used to prevent errors
                
                %In the case of the beginning of a branch
                case '('
                    %The maximum used branchlevel is upped by one and
                    %becomes the new value for 'branchlvl'
                    branchlvl = max([main.branch 0])+1;
                    %The branchdepth is increased by one
                    branchdepth = branchdepth+1;
                    kstor = 0;
                    break
                    
                %In the case of the end of a branch
                case ')'
                    %'branchdepth' Is lowered by one
                    branchdepth = branchdepth-1;
                    %The 'branchlvl' is restored to the correct number
                    %since simply decreasing it by one would not be
                    %adequate in the case of multiple branches on one atom
                    test = [main.branch];
                    branchlvl = test(max(find([main.branchdepth] == branchdepth)));
                    kstor = 0;
                    break
                    
                %In the case of a double bond
                case '='
                    %Set the bondtype to two
                    main(pos+j).bondtype = 2;
                    kstor = 0;
                    break
                    
                %In the case of a triple bond
                case '#'
                    %Set the bondtype to three
                    main(pos+j).bondtype = 3;
                    kstor = 0;
                    break
                    
                %In the case of a quadruple bond
                case '$'
                    %Set the bondtype to four
                    main(pos+j).bondtype = 4;
                    kstor = 0;
                    break
                    
                %In the case of an aromatic bond
                case ':'
                    %Set 'aromatic' to true
                    main(pos+j).aromatic = true;
                    kstor = 0;
                    break
                    
                %In the case of a square bracket
                case '['
                    %Find the corrosponding ending bracket
                    endPos = findEndSq(pos+j-1,piece);
                    %Determine the range
                    a = [pos+j-1 endPos];
                    %Store the difference in 'kstor'
                    kstor = a(2)-a(1);
                    %Use the function 'sqBrackets' to read what is inside
                    %of the brackets and add branchlevel and branchdepth if
                    %necessary.
                    main = sqBrackets(piece(2:kstor),main,pos+j-1);
                    if branchdepth
                        main(pos+j-1).branch = branchlvl;
                        main(pos+j-1).branchdepth = branchdepth;
                    else
                        main(pos+j-1).branchdepth = 0;
                    end
                    break
                    
                %In the case of an "ion bond"
                case '.'
                    %Store the dot as 'element'
                    main(pos+j-1).element = '.';
                    kstor = 0;
                    %Store aromatic false to prevent errors with reading
                    %the field
                    main(pos+j-1).aromatic = false;
                    break
                    
                %In the case of chirality
                case '\'
                    %Finds the position of the first backslash, and
                    %forwardslash, and stores the positions in backPos and
                    %forPos
                    backPos = find(piece(pos+1:length(piece)) == '\',1);
                    forPos = find(piece(pos+1:length(piece)) == '/',1);
                    if ~isempty(forPos) && ~isempty(backPos)
                        % If both variables contain a position, the first
                        % position decides which double bond configure is
                        % present.
                        if backPos < forPos % \  \ = Entgegen
                            main(j+backPos-1).dubbondconfig = 'E';
                        elseif backPos > forPos % \  / = Zusammen
                            main(j+forPos-1).dubbondconfig = 'Z';
                        end
                    elseif isempty(forPos) && ~isempty(backPos)
                        % as there is only one known position, we use that
                        % one to specify the double bond configuration.
                        main(j+backPos-1).dubbondconfig = 'E';
                    elseif isempty(backPos) && ~isempty(forPos)
                        % as there is only one known position, we use that
                        % one to specify the double bond configuration.
                        main(j+forPos-1).dubbondconfig = 'Z';
                    else
                        %last found, do nothing.
                    end
                    kstor = 0;
                    break
                case '/'
                    backPos = find(piece(pos+1:length(piece)) == '\',1);
                    forPos = find(piece(pos+1:length(piece)) == '/',1);
                    %Finds the position of the first backslash, and
                    %forwardslash, and stores the positions in backPos and
                    %forPos
                    if ~isempty(forPos) && ~isempty(backPos)
                        % If both variables contain a position, the first
                        % position decides which double bond configure is
                        % present.
                        if backPos < forPos % /  \ = Zusammen
                            main(j+backPos-1).dubbondconfig = 'Z';
                        elseif backPos > forPos % /  / = Entgegen
                            main(j+forPos-1).dubbondconfig = 'E';
                        end
                    elseif isempty(forPos) && ~isempty(backPos)
                        % as there is only one known position, we use that
                        % one to specify the double bond configuration.
                        main(j+backPos-1).dubbondconfig = 'Z';
                    elseif isempty(backPos) && ~isempty(forPos)
                        main(j+forPos-1).dubbondconfig = 'E';
                        % as there is only one known position, we use that
                        % one to specify the double bond configuration.
                    else
                        %last found, do nothing.
                    end
                    kstor = 0;
                    break
                    
            end
        end
    end
    %If the length of main is larger or equal to pos+j-1, make sure branch
    %and branchdepth are not empty.
    if length(main)>=pos+j-1
        if isempty(main(pos+j-1).branch)
            main(pos+j-1).branch = 0;
            main(pos+j-1).branchdepth = 0;
        end
    end
    
    %Cut the read piece away:
    piece = piece(kstor+2:length(piece));
end

%% Cleanup
%Remove all elements in 'main' that do not have anything in the field
%'element' since all those elements have no further use.
j = 0;
while j < length(main)
    j = j+1;
    if isempty(main(j).element)
        main(j) = [];
        j = j-1;
    end
end

%Making sure the field that are needed from now on exist.
if ~isempty(main)
    if ~myIsField(main,'ringmarker')
        main(pos).ringmarker = [];
    end
    if ~myIsField(main,'bondtype')
        main(pos).bondtype = [];
    end
    if ~myIsField(main,'isotope')
        main(pos).isotope = [];
    end
    if ~myIsField(main,'charge')
        main(pos).charge = [];
    end
    if ~myIsField(main,'hydrogen')
        main(pos).hydrogen = [];
    end
end

%% End
end